
#include <stdio.h>
#include <apr_atomic.h>
#include "../aprtools/APRPRNG.h"
#include "APRInterface.h"
#include "debug.h"

APRInterface *APRInterface::apr_iface_singleton = NULL;

/** Get singleton instance (prevents double initialisation) */
APRInterface &APRInterface::getInstance()
{
   if (apr_iface_singleton == NULL)
      apr_iface_singleton = new APRInterface();
   return *apr_iface_singleton;
}

/** Get singleton instance (prevents double initialisation, but passes
 * arguments) */
APRInterface &APRInterface::getInstance(int *argc, const char *const **argv)
{
   if (apr_iface_singleton == NULL)
      apr_iface_singleton = new APRInterface(argc, argv);
   return *apr_iface_singleton;
}

/** Initialises the APR library. */
APRInterface::APRInterface()
{
   isinit = 0;
   if (apr_initialize() == APR_SUCCESS) APRInit(1);
}

/** Initialises the APR library. with space for passing arguments to
 * the APR library. */
APRInterface::APRInterface(int *argc, const char *const **argv)
{
   isinit = 0;
   if (*argv)
   {
      if (apr_app_initialize(argc, argv, NULL) == APR_SUCCESS) APRInit(1);
   }
   else
   {
      if (apr_initialize() == APR_SUCCESS) APRInit(1);
   }
}

/** Destructor for the class, also clears, destroys and frees the
 * library structures. */
APRInterface::~APRInterface()
{
   if (isinit)
   {
      APRPRNG prng;
      prng.forceDestruction();
      isinit = 0;
      //apr_pool_clear(mp);
      //apr_pool_destroy(mp);
      //apr_terminate();
   }
}

/** Creates the top level memory pool and if successful, sets the flag
 * to 'initialised successfully'.
 * 
 * @param inited Whether the previous stage completed successfully. */
void APRInterface::APRInit(int inited)
{
   apr_status_t status;
   status = apr_pool_create(&mp, NULL);
   CheckAPRError(status);
   isinit = inited & (status == APR_SUCCESS);
   status = apr_atomic_init(mp);
   CheckAPRError(status);
   if (status != APR_SUCCESS)
      errprint("APR atomics have not been initialised correctly!\n"); 
}

#define APR_INTERFACE_ERROR_DESCRIPTION_BUFFER_SIZE 0x100

/** Wrapper function for generating textual errors from APR library
 * error codes.
 * 
 * @param status APR library error code.
 * 
 * @param fpretty Pretty printed function name where the error
 * originated from.
 * 
 * @param line Line number where the error originated from. */
void APRInterface::func_CheckAPRError(apr_status_t status, const char *fpretty, int line)
{
   if (status == 0) return;
   char buffer[APR_INTERFACE_ERROR_DESCRIPTION_BUFFER_SIZE];
   char *terror = apr_strerror(status, buffer, APR_INTERFACE_ERROR_DESCRIPTION_BUFFER_SIZE);
   errprintpd("%s", fpretty, line, terror);
}

/** Get the pointer to the top level memory pool.
 * 
 * @return Pointer to the main memory pool. */
apr_pool_t *APRInterface::getGlobalPool()
{
   return mp;
}

/** Check whether the library was successfully initialised or not.
 * 
 * @return One if was initialised, zero if a failure occured. */
int APRInterface::wasSuccessfullyInitialised()
{
   return isinit;
}

/** Destroy the singleton. */
void APRInterface::destroyInstance()
{
   delete apr_iface_singleton;
   apr_iface_singleton = NULL;
}
